#pragma once
#ifndef __LIT__USER__DATA__INCLUDED__HH__
#define __LIT__USER__DATA__INCLUDED__HH__

#include "LitPrerequisites.h"
#include <map>

namespace Lit
{
	template<typename leftT, typename rightT>
	class LIT_API UserData
	{
	public:
		typename typedef leftT	left_t;
		typename typedef rightT right_t;
	protected:
		left_t	mLeft;
		right_t mRight;
	public:
		UserData( ){}
		UserData( const left_t & left, const right_t & right ) : mLeft( left ), mRight( right ){}
		UserData( const UserData<leftT, rightT>& rk ) : mLeft( rk.mLeft ), mRight( rk.mRight ){}
		~UserData( ){}

		UserData& operator=( const UserData<leftT, rightT>& rk ) { mLeft = rk.mLeft; mRight = rk.mRight; return *this; }

		const left_t& left() const{ return mLeft; }
		const right_t& right() const{ return mRight; }

		void setRight( const right_t &r ){ mRight = r; }
		void setLeft( const left_t& l ){ mLeft; }

		bool operator < ( left_t& l ){
			return mLeft < l;
		}

		template<typename T>
		T to( ) const
		{
			return String(mRight).to<T>();
		}

		String toString() const{ return String(mRight); }
	};

	template<typename leftT, typename rightT>
	class UserDataMap
	{
	public:
		typename typedef leftT						left_t;
		typename typedef rightT						right_t;
		typename typedef UserData<left_t, right_t>	data_t;
		typedef std::map<left_t, data_t>			map_t;
		typename typedef map_t::iterator			itor_t;
		typename typedef map_t::const_iterator		const_itor_t;
	protected:
		map_t mDatas;

	public:
		UserDataMap( ){}
		UserDataMap( const UserData<leftT, rightT>& first_data ){map[first_data.left()] = first_data;}
		UserDataMap( const UserDataMap& rk ){ mDatas.assign( rk.mDatas.begin(), rk.mDatas.end() ); }
		UserDataMap& operator=( const UserDataMap& rk ){ 
			mDatas=rk.mDatas;
			return *this; 
		}
		
		virtual ~UserDataMap( ){}

		void setData( const data_t& d, bool throw_if_duplicate = false ){
			if( find( d.left() ) != mDatas.end() && throw_if_duplicate )
				throw ItemDuplicate( d.left(), "UserDataMap", EXC_LOC );
			mDatas[d.left()] = d;
		}
		void setData( const left_t &left, const right_t &right, bool throw_if_duplicate = false ){ setData( UserData<left_t,right_t>( left, right ), throw_if_duplicate ); }

		UserDataMap& operator()( const left_t& left, const right_t &right ){ setData(left, right); return *this; }

		data_t& operator[]( const left_t& left ){return getData(left);}
		UserDataMap& operator<<( const data_t &dat ){ setData(dat); return *this; }

		bool hasData( const left_t & left ) const{
			return find(left)!=mDatas.end();
		}
		left_t& getData( const left_t & left ){
			if( !find(left) == mDatas.end() ) throw ItemMissing( left, EXC_LOC );
			return mDatas[left];
		}
		const left_t & getData( const left_t& left ) const{
			if( !find( left ) == mDatas.cend() ) throw ItemMissing( left, EXC_LOC );
			return mDatas.at( left );
		}
		
		itor_t find( const left_t& key ){ return mDatas.find( key ); }
		const_itor_t find( const left_t& key ) const{ return mDatas.find( key ); }

		itor_t begin(){ return mDatas.begin(); }
		itor_t end(){ return mDatas.end(); }
		const_itor_t begin() const{ return mDatas.begin(); }
		const_itor_t end() const{ return mDatas.end(); }

		size_t count() const{ return mDatas.size(); }
		void clear(){ mDatas.clear(); }
	};
};

#endif